/*
* Copyright 2011 cruxframework.org.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.cruxframework.crux.core.rebind.screen.widget;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import org.cruxframework.crux.core.client.Crux;
import org.cruxframework.crux.core.client.controller.RegisteredControllers;
import org.cruxframework.crux.core.client.datasource.DataSource;
import org.cruxframework.crux.core.client.datasource.RegisteredDataSources;
import org.cruxframework.crux.core.client.formatter.RegisteredClientFormatters;
import org.cruxframework.crux.core.client.ioc.IocContainer;
import org.cruxframework.crux.core.client.screen.DeviceAdaptive.Device;
import org.cruxframework.crux.core.client.screen.DeviceAdaptive.Input;
import org.cruxframework.crux.core.client.screen.DeviceAdaptive.Size;
import org.cruxframework.crux.core.client.screen.InterfaceConfigException;
import org.cruxframework.crux.core.client.screen.LazyPanelWrappingType;
import org.cruxframework.crux.core.client.screen.binding.DataObjectBinder;
import org.cruxframework.crux.core.client.screen.binding.NativeWrapper;
import org.cruxframework.crux.core.client.screen.views.BindableView;
import org.cruxframework.crux.core.client.screen.views.View.RenderCallback;
import org.cruxframework.crux.core.client.screen.views.ViewActivateEvent;
import org.cruxframework.crux.core.client.screen.views.ViewActivateHandler;
import org.cruxframework.crux.core.client.screen.views.ViewDeactivateEvent;
import org.cruxframework.crux.core.client.screen.views.ViewDeactivateHandler;
import org.cruxframework.crux.core.client.screen.views.ViewFactory;
import org.cruxframework.crux.core.client.screen.views.ViewFactoryUtils;
import org.cruxframework.crux.core.client.screen.views.ViewLoadEvent;
import org.cruxframework.crux.core.client.screen.views.ViewLoadHandler;
import org.cruxframework.crux.core.client.screen.views.ViewPanel;
import org.cruxframework.crux.core.client.screen.views.ViewUnloadEvent;
import org.cruxframework.crux.core.client.screen.views.ViewUnloadHandler;
import org.cruxframework.crux.core.client.utils.EscapeUtils;
import org.cruxframework.crux.core.client.utils.ScriptTagHandler;
import org.cruxframework.crux.core.client.utils.StringUtils;
import org.cruxframework.crux.core.declarativeui.ViewParser;
import org.cruxframework.crux.core.rebind.AbstractProxyCreator;
import org.cruxframework.crux.core.rebind.CruxGeneratorException;
import org.cruxframework.crux.core.rebind.context.RebindContext;
import org.cruxframework.crux.core.rebind.context.scanner.ControllerScanner;
import org.cruxframework.crux.core.rebind.context.scanner.ResourceNotFoundException;
import org.cruxframework.crux.core.rebind.controller.ControllerProxyCreator;
import org.cruxframework.crux.core.rebind.controller.RegisteredControllersProxyCreator;
import org.cruxframework.crux.core.rebind.datasource.RegisteredDataSourcesProxyCreator;
import org.cruxframework.crux.core.rebind.formatter.RegisteredClientFormattersProxyCreator;
import org.cruxframework.crux.core.rebind.ioc.IocContainerRebind;
import org.cruxframework.crux.core.rebind.screen.DataProvider;
import org.cruxframework.crux.core.rebind.screen.Event;
import org.cruxframework.crux.core.rebind.screen.View;
import org.cruxframework.crux.core.rebind.screen.View.NativeDataBinding;
import org.cruxframework.crux.core.rebind.screen.resources.ResourcesHandlerProxyCreator;
import org.cruxframework.crux.core.rebind.screen.widget.declarative.DeclarativeFactory;
import org.cruxframework.crux.core.utils.JClassUtils;
import org.cruxframework.crux.core.utils.RegexpPatterns;
import org.json.JSONObject;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.core.ext.CachedGeneratorResult;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.dev.generator.NameFactory;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Node;
import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.event.logical.shared.AttachEvent.Handler;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.logging.client.LogConfiguration;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.ClosingEvent;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
/**
* @author Thiago da Rosa de Bustamante
*
*/
public class ViewFactoryCreator extends AbstractProxyCreator
{
private static Map<String, WidgetCreator<?>> creators = new HashMap<String, WidgetCreator<?>>();
private static NameFactory nameFactory = new NameFactory();
private static String viewVariable = "__view";
protected ViewBindHandler bindHandler;
protected ControllerAccessHandler controllerAccessHandler;
protected String iocContainerClassName;
protected View view;
protected WidgetConsumer widgetConsumer;
private Map<String, Boolean> attachToDOMFactories = new HashMap<String, Boolean>();
private ViewDataBindingsProcessor dataBindingProcessor;
private DataProviderHelper dataProviderHelper;
private Map<String, String> declaredMessages = new HashMap<String, String>();
private String device;
private final LazyPanelFactory lazyFactory;
private final Set<String> lazyPanels = new HashSet<String>();
private String loggerVariable;
private String nativeControllers;
private final LinkedList<PostProcessingData> postProcessingCode = new LinkedList<PostProcessingData>();
private Set<String> resources;
private Set<String> rootPanelChildren;
private boolean viewChanged;
private String viewPanelInitializedVariable;
private String viewPanelVariable;
/**
* Constructor
*
* @param context
* @param logger
* @param view
* @param viewChanged
* @param device
* @param module
*/
public ViewFactoryCreator(RebindContext context, View view, boolean viewChanged, String device)
{
super(context, true);
this.view = view;
this.viewChanged = viewChanged;
this.device = device;
this.lazyFactory = new LazyPanelFactory(this);
this.loggerVariable = createVariableName("logger");
this.viewPanelVariable = createVariableName("viewPanel");
this.viewPanelInitializedVariable = createVariableName("viewPanelInitialized");
this.widgetConsumer = new ViewWidgetConsumer(this);
this.dataBindingProcessor = new ViewDataBindingsProcessor(this);
this.dataProviderHelper = new DataProviderHelper(this);
this.rootPanelChildren = new HashSet<String>();
this.controllerAccessHandler = new DefaultControllerAccessor(viewVariable, context.getControllers());
this.bindHandler = new ViewBindHandler(context, view, this);
}
/**
* Retrieve the variable name for the dataObjectBinder associated with the given alias.
* @param dataObjectAlias
* @param out
* @return
*/
public String getDataObjectBinderVariable(String dataObjectAlias, SourcePrinter out)
{
return bindHandler.getDataObjectBinderVariable(dataObjectAlias, out);
}
public JClassType getDataObjectFromProvider(String dataProviderId)
{
return dataProviderHelper.getDataObjectFromProvider(dataProviderId);
}
/**
*
* @param propertyValue
* @param widgetClassName
* @param widgetPropertyPath
* @param uiObjectClassName
* @param getUiObjectExpression
* @param dataBindingProcessor
* @param setterMethod
* @param propertyTypeName
* @return
*/
public ExpressionDataBinding getExpressionDataBinding(String propertyValue, String widgetClassName, String widgetPropertyPath,
String uiObjectClassName, String getUiObjectExpression,
DataBindingProcessor dataBindingProcessor,
String setterMethod, String propertyTypeName)
{
return bindHandler.getExpressionDataBinding(propertyValue, widgetClassName,
widgetPropertyPath, uiObjectClassName, getUiObjectExpression, dataBindingProcessor, setterMethod, propertyTypeName);
}
/**
*
* @param propertyValue
* @param widgetClassName
* @param widgetPropertyPath
* @param boundToAttribute
* @param uiObjectClassName
* @param getUiObjectExpression
* @param dataBindingProcessor
* @return
*/
public PropertyBindInfo getObjectDataBinding(String propertyValue, String widgetClassName, String widgetPropertyPath,
boolean boundToAttribute, String uiObjectClassName, String getUiObjectExpression,
DataBindingProcessor dataBindingProcessor)
{
return bindHandler.getObjectDataBinding(propertyValue, widgetClassName, widgetPropertyPath, boundToAttribute,
uiObjectClassName, getUiObjectExpression, dataBindingProcessor);
}
/**
* Return the qualified name of the ViewFactory class created for the associated screen
* @return
*/
public String getProxyQualifiedName()
{
return ViewFactory.class.getPackage().getName() + "." + getProxySimpleName();
}
/**
* Return the simple name of the ViewFactory class created for the associated screen
* @return
*/
public String getProxySimpleName()
{
String className = view.getId()+"_"+this.device;
className = className.replaceAll("[\\W]", "_");
return className;
}
/**
*
* @return
*/
public String getViewSuperClassName()
{
if (isBindableView())
{
return BindableView.class.getCanonicalName()+"<"+context.getDataObjects().getDataObject(view.getDataObject())+">";
}
return "View";
}
/**
* Close the current postProcessing scope and schedule the execution of all scope commands.
*
* @param printer
*/
protected void commitPostProcessing(SourcePrinter printer)
{
PostProcessingData postProcessingData = this.postProcessingCode.removeLast();
String postProcessingCode = postProcessingData.toString();
if (!StringUtils.isEmpty(postProcessingCode))
{
printer.println(Scheduler.class.getCanonicalName()+".get().scheduleDeferred(new "+
ScheduledCommand.class.getCanonicalName()+"(){");
printer.println("public void execute(){");
printer.print(postProcessingCode);
printer.println("}");
printer.println("});");
}
}
/**
* Create a new scope for the post processing commands. All commands added by
* {@code printlnPostProcessing} method will be added to this same scope, what means
* that they will be fired together. When {@code commitPostProcessing} method is called,
* the scope is closed and all scope commands are programmed for execution.
*/
protected void createPostProcessingScope()
{
this.postProcessingCode.add(new PostProcessingData());
}
@Override
protected boolean findCacheableImplementationAndMarkForReuseIfAvailable()
{
CachedGeneratorResult lastResult = context.getGeneratorContext().getCachedGeneratorResult();
if (lastResult == null || !context.getGeneratorContext().isGeneratorResultCachingEnabled())
{
return false;
}
String proxyName = getProxyQualifiedName();
// check that it is available for reuse
if (!lastResult.isTypeCached(proxyName))
{
return false;
}
if (!viewChanged)
{
return context.getGeneratorContext().tryReuseTypeFromCache(proxyName);
}
return false;
}
protected void generateCreateDataObjectMethod(SourcePrinter printer)
{
String dataObjectClass = context.getDataObjects().getDataObject(view.getDataObject());
printer.println("protected "+ dataObjectClass +" createDataObject(){");
printer.println("return GWT.create("+dataObjectClass+".class);");
printer.println("}");
}
protected void generateGetIocContainerMethod(SourcePrinter printer)
{
printer.println("public "+ IocContainer.class.getCanonicalName() +" getIocContainer(){");
printer.println("return iocContainer;");
printer.println("}");
printer.println("public "+ iocContainerClassName +" getTypedIocContainer(){");
printer.println("return iocContainer;");
printer.println("}");
}
protected void generateGetViewPanelMethod(SourcePrinter printer)
{
printer.println("public "+ViewPanel.class.getCanonicalName()+" getViewPanel(){");
printer.println("return "+viewPanelVariable + ";");
printer.println("}");
}
/**
* Generate the View Constructor
*/
@Override
protected void generateProxyContructor(SourcePrinter printer) throws CruxGeneratorException
{
String regsiteredControllersClass = new RegisteredControllersProxyCreator(context, view, iocContainerClassName, device).create();
String regsiteredDataSourcesClass = new RegisteredDataSourcesProxyCreator(context, view, iocContainerClassName, device).create();
String regsiteredFormattersClass = new RegisteredClientFormattersProxyCreator(context, view).create();
printer.println("protected "+getProxySimpleName()+"(String id){");
printer.println("super(id);");
printer.println("setTitle("+resolveI18NString(view.getTitle())+");");
printer.println("this.iocContainer = new "+iocContainerClassName+"(this);");
printer.println("this.registeredControllers = new "+regsiteredControllersClass+"(this, iocContainer);");
printer.println("this.registeredFormatters = new "+regsiteredFormattersClass+"();");
printer.println("this.registeredDataSources = new "+regsiteredDataSourcesClass+"(this, iocContainer);");
generateResources(printer);
printer.println("new " + nativeControllers + "(this).init();");
printer.println("}");
}
/**
* Generate the View fields
*
* @param printer
*/
protected void generateProxyFields(SourcePrinter printer)
{
printer.println("private "+RegisteredControllers.class.getCanonicalName()+" registeredControllers;");
printer.println("private "+RegisteredDataSources.class.getCanonicalName()+" registeredDataSources;");
printer.println("private "+RegisteredClientFormatters.class.getCanonicalName()+" registeredFormatters;");
printer.println("protected "+ iocContainerClassName +" iocContainer;");
for (String messageClass: declaredMessages.keySet())
{
printer.println("private "+messageClass+" "+declaredMessages.get(messageClass) + " = GWT.create("+messageClass+".class);");
}
printer.println("private final "+getViewSuperClassName()+" "+viewVariable+" = this;");
printer.println("private static "+Logger.class.getCanonicalName()+" "+loggerVariable+" = "+
Logger.class.getCanonicalName()+".getLogger("+getProxySimpleName()+".class.getName());");
printer.println("private "+ViewPanel.class.getCanonicalName()+" "+viewPanelVariable+" = null;");
printer.println("private boolean "+viewPanelInitializedVariable+" = false;");
}
/**
* Generate the View methods.
*
* @param printer
*/
protected void generateProxyMethods(SourcePrinter printer)
{
if(printer != null)
{
generateGetRegisteredControllersMethod(printer);
generateGetRegisteredFormattersMethod(printer);
generateCreateDataSourceMethod(printer);
generateCreateWidgetsMethod(printer);
generateRenderMethod(printer);
generateUpdateDimensionsMethods(printer);
generateInitializeLazyDependenciesMethod(printer);
generateGetIocContainerMethod(printer);
generateRegisterDataObjectBindersMethod(printer);
generateGetViewPanelMethod(printer);
if (isBindableView())
{
generateCreateDataObjectMethod(printer);
}
}
}
protected void generateRegisterDataObjectBindersMethod(SourcePrinter printer)
{
printer.println("protected void registerDataObjectBinders(){");
Iterator<String> dataObjects = bindHandler.iterateDataObjects();
while (dataObjects.hasNext())
{
String dataObjectAlias = dataObjects.next();
String dataObjectClass = context.getDataObjects().getDataObject(dataObjectAlias);
try
{
JClassType dataObjectType = context.getGeneratorContext().getTypeOracle().getType(dataObjectClass);
JClassType javaScriptObjectType = context.getGeneratorContext().getTypeOracle().findType(JavaScriptObject.class.getCanonicalName());
printer.println("addDataObjectBinder(new "+DataObjectBinder.class.getCanonicalName()+"<"+dataObjectClass+">(this){");
printer.println("protected "+dataObjectClass+" createDataObject() {");
if (dataObjectType.isAssignableTo(javaScriptObjectType))
{
printer.println(dataObjectClass+" obj = "+dataObjectClass+".createObject().cast();");
printer.println("return obj;");
}
else
{
printer.println("return GWT.create("+dataObjectClass+".class);");
}
printer.println("}");
printer.println("}, "+EscapeUtils.quote(dataObjectAlias)+");");
}
catch (NotFoundException e)
{
throw new CruxGeneratorException("DataObject class ["+dataObjectClass+"] not found", e);
}
}
printer.println("}");
}
/**
* Create ClientBundles for the declared resources on View
* @param printer
*/
protected void generateResources(SourcePrinter printer)
{
for (String resourceClass : resources)
{
printer.println(resourceClass+".init();");
}
}
@Override
protected void generateSubTypes(SourcePrinter srcWriter) throws CruxGeneratorException
{
iocContainerClassName = new IocContainerRebind(context, view, device).create();
resources = new HashSet<String>();
Iterator<String> resources = view.iterateResources();
while (resources.hasNext())
{
String resourceKey = resources.next();
this.resources.add(new ResourcesHandlerProxyCreator(context, resourceKey, view, device).create());
}
nativeControllers = new NativeControllersProxyCreator(this).create();
}
/**
* @return
*/
protected RebindContext getContext()
{
return context;
}
/**
* Retrieve the object responsible for print controller access expressions on client JS
* @return
*/
protected ControllerAccessHandler getControllerAccessHandler()
{
return this.controllerAccessHandler;
}
/**
* Gets the code necessary to access a i18n declared property or the own property, if
* it is not in declarative i18n format.
*
* @param property
* @return
*/
protected String getDeclaredMessage(String property)
{
if (isKeyReference(property))
{
if (isResourceReference(property))
{
return getResourceAccessExpression(property);
}
else
{
String[] messageParts = getKeyMessageParts(property);
String messageClassName = context.getMessages().getMessageClass(messageParts[0]);
// Checks if declared message is valid
this.checkDeclaredMessage(messageClassName, messageParts[0], messageParts[1]);
String messageVariable;
if (!declaredMessages.containsKey(messageClassName))
{
messageVariable= createVariableName("mesg");
declaredMessages.put(messageClassName, messageVariable);
}
else
{
messageVariable = declaredMessages.get(messageClassName);
}
return messageVariable+"."+messageParts[1]+"()";
}
}
else
{
return property==null?null:EscapeUtils.quote(property);
}
}
/**
* Gets all messages declared on this screen
* @return
*/
protected Map<String, String> getDeclaredMessages()
{
return declaredMessages;
}
/**
*
* @return
*/
protected String getDevice()
{
return this.device;
}
/**
* @return
*/
protected TreeLogger getLogger()
{
return context.getLogger();
}
/**
* Retrieves the logger variable name
* @return
*/
protected String getLoggerVariable()
{
return loggerVariable;
}
/**
* Return the type of a given crux meta tag. This type could be {@code "screen"}
* or another string referencing a registered {@code WidgetFactory}.
*
* @param cruxMetaElement
* @return
*/
protected String getMetaElementType(JSONObject cruxMetaElement)
{
return cruxMetaElement.optString("_type");
}
/**
* Retrieve the current PostProcessingPrinter
* @return
*/
protected SourcePrinter getPostProcessingPrinter()
{
return this.postProcessingCode.getLast().postProcessingPrinter;
}
/**
* Gets the code necessary to access a resource property or the own property, if
* it is not in a resource reference format.
*
* @param property
* @return
*/
protected String getResourceAccessExpression(String property)
{
if (isResourceReference(property))
{
String[] resourceParts = getResourceParts(property);
String resourceKey = resourceParts[0];
String resourceProperty = resourceParts[1];
String resourceClassName = context.getResources().getResource(resourceKey, Device.valueOf(device));
if (!view.useResource(resourceKey))
{
throw new CruxGeneratorException("The resource ["+resourceKey+"] is not imported into view ["+view.getId()+"]. Use the useResource atribute of view tag to import it first.");
}
String resourceObject = "(("+resourceClassName+")getResource("+EscapeUtils.quote(resourceKey)+"))";
StringBuilder out = new StringBuilder();
JClassType resourceType = context.getGeneratorContext().getTypeOracle().findType(resourceClassName);
if (resourceType == null)
{
String message = "Resource ["+resourceKey+"] , declared on view ["+view.getId()+"], could not be loaded. "
+ "\n Possible causes:"
+ "\n\t 1. Check if any type or subtype used by resource refers to another module and if this module is inherited in the .gwt.xml file."
+ "\n\t 2. Check if your resource or its members belongs to a client package."
+ "\n\t 3. Check the versions of all your modules."
;
throw new CruxGeneratorException(message);
}
try
{
JClassUtils.buildGetValueExpression(out, resourceType, resourceProperty, resourceObject, false);
}
catch (NoSuchFieldException e)
{
throw new CruxGeneratorException("Resource ["+resourceKey+"] , declared on view ["+view.getId()+"], has an invalid expression ["+resourceProperty+"]", e);
}
return out.toString();
}
else
{
return property==null?null:EscapeUtils.quote(property);
}
}
/**
* Creates and returns a new {@link SourceWriter}
* @return a new {@link SourceWriter}
*/
protected SourcePrinter getSourcePrinter()
{
String packageName = ViewFactory.class.getPackage().getName();
PrintWriter printWriter = context.getGeneratorContext().tryCreate(context.getLogger(), packageName, getProxySimpleName());
if (printWriter == null)
{
return null;
}
ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(packageName, getProxySimpleName());
composerFactory.setSuperclass(getViewSuperClassName());
String[] imports = getImports();
for (String imp : imports)
{
composerFactory.addImport(imp);
}
return new SourceCodePrinter(composerFactory.createSourceWriter(context.getGeneratorContext(), printWriter), context.getLogger());
}
/**
* Create a new printer for a subType. That subType will be declared on the same package of the
* {@code ViewFactory}.
*
* @param packageName
* @param subType
* @param superClass
* @param interfaces
* @param imports
* @param isInterface
* @return
*/
protected SourcePrinter getSubTypeWriter(String packageName, String subType, String superClass, String[] interfaces, String[] imports)
{
return getSubTypeWriter(packageName, subType, superClass, interfaces, imports, false);
}
/**
* Create a new printer for a subType. That subType will be declared on the package name informed in the first parameter
* if packageName isEmpty, subType will be declared on the same package of the { @code ViewFactory }.
*
* @param packageName
* @param subType
* @param superClass
* @param interfaces
* @param imports
* @param isInterface
* @return
*/
protected SourcePrinter getSubTypeWriter(String packageName, String subType, String superClass, String[] interfaces, String[] imports, boolean isInterface)
{
if(StringUtils.isEmpty(packageName))
{
packageName = ViewFactory.class.getPackage().getName();
}
PrintWriter printWriter = context.getGeneratorContext().tryCreate(context.getLogger(), packageName, subType);
if (printWriter == null)
{
return null;
}
ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(packageName, subType);
if (isInterface)
{
composerFactory.makeInterface();
}
if (imports != null)
{
for (String imp : imports)
{
composerFactory.addImport(imp);
}
}
if (superClass != null)
{
composerFactory.setSuperclass(superClass);
}
if (interfaces != null)
{
for (String intf : interfaces)
{
composerFactory.addImplementedInterface(intf);
}
}
return new SourceCodePrinter(composerFactory.createSourceWriter(context.getGeneratorContext(), printWriter), context.getLogger());
}
/**
* Create a new printer for a subType. That subType will be declared on the same package of the
* {@code ViewFactory}.
*
* @param subType
* @param superClass
* @param interfaces
* @param imports
* @return
*/
protected SourcePrinter getSubTypeWriter(String subType, String superClass, String[] interfaces, String[] imports)
{
return getSubTypeWriter(subType, superClass, interfaces, imports, false);
}
/**
* Create a new printer for a subType. That subType will be declared on the same package of the
* {@code ViewFactory}.
*
* @param subType
* @param superClass
* @param interfaces
* @param imports
* @param isInterface
* @return
*/
protected SourcePrinter getSubTypeWriter(String subType, String superClass, String[] interfaces, String[] imports, boolean isInterface)
{
return getSubTypeWriter(null, subType, superClass, interfaces, imports, isInterface);
}
/**
* @return
*/
protected View getView()
{
return this.view;
}
/**
* Process the given HTML code. It handles the placeholder div elements for crux widgets as any resource declaration.
* @param html
* @return
*/
protected String getViewHTML(String html)
{
String result = resolveI18NString(html).replace(ViewParser.CRUX_VIEW_PREFIX, "\"+"+getViewVariable()+".getPrefix()+\"");
return result;
}
/**
* Returns the creator of the widgets of the given type.
* @param widgetType
* @return the creator of the widgets of the given type.
*/
protected WidgetCreator<?> getWidgetCreator(String widgetType)
{
try
{
if (!creators.containsKey(widgetType))
{
String creatorClassName = WidgetLibraries.getInstance().getFactoryClass(widgetType);
Class<?> widgetCreator = Class.forName(creatorClassName);
WidgetCreator<?> factory = (WidgetCreator<?>) widgetCreator.newInstance();
creators.put(widgetType, factory);
}
}
catch (Exception e)
{
throw new CruxGeneratorException("Error retrieveing widgetFactory for type ["+widgetType+"]."
+ "\n Possible cause:"
+ "\n\t 1. Check if your resource file (View, Template, Screen ...) is validated according to the Crux Catalog."
,e);
}
WidgetCreator<?> factory = creators.get(widgetType);
factory.setViewFactory(this);
return factory;
}
/**
*
* @return
*/
protected boolean isBindableView()
{
return !StringUtils.isEmpty(view.getDataObject());
}
/**
* Returns <code>true</code> if the given text is an internationalization key.
* @param text
* @return <code>true</code> if the given text is an internationalization key.
*/
protected boolean isKeyReference(String text)
{
return text!= null && RegexpPatterns.REGEXP_CRUX_MESSAGE.matcher(text).matches();
}
/**
* Returns <code>true</code> if the given text is a reference to a resource.
* @param text
* @return <code>true</code> if the given text is a reference to a resource.
*/
protected boolean isResourceReference(String text)
{
if (text!= null && RegexpPatterns.REGEXP_CRUX_RESOURCE.matcher(text).matches())
{
String[] parts = getResourceParts(text);
return (view.useResource(parts[0]));
}
return false;
}
/**
* Check if the given widget is available for postProcessing
* @param widgetId widget identifier
* @return true if available
*/
protected boolean isWidgetRegisteredForPostProcessing(String widgetId)
{
return this.postProcessingCode.getLast().referencedWidgets.contains(widgetId);
}
/**
* Creates a new widget based on its meta-data element.
*
* @param printer
* @param metaElem
* @param widgetId
* @return
* @throws CruxGeneratorException
*/
protected String newWidget(SourcePrinter printer, JSONObject metaElem, String widgetId, String widgetType) throws CruxGeneratorException
{
return newWidget(printer, metaElem, widgetId, widgetType, this.widgetConsumer, this.dataBindingProcessor);
}
/**
* Creates a new widget based on its meta-data element.
*
* @param printer
* @param metaElem
* @param widgetId
* @param consumer
* @param dataBindingProcessor
* @return
* @throws CruxGeneratorException
*/
protected String newWidget(SourcePrinter printer, JSONObject metaElem, String widgetId, String widgetType,
WidgetConsumer consumer, DataBindingProcessor dataBindingProcessor)
throws CruxGeneratorException
{
WidgetCreator<?> widgetFactory = getWidgetCreator(widgetType);
if (widgetFactory == null)
{
throw new CruxGeneratorException("Can not found widgetFactory for type: ["+widgetType+"].");
}
String widget;
if (consumer != null && consumer instanceof LazyCompatibleWidgetConsumer && mustRenderLazily(widgetType, metaElem, widgetId))
{
String lazyPanelId = ViewFactoryUtils.getLazyPanelId(widgetId, LazyPanelWrappingType.wrapWholeWidget);
lazyPanels.add(lazyPanelId);
widget = lazyFactory.getLazyPanel(printer, metaElem, widgetId, LazyPanelWrappingType.wrapWholeWidget);
consumer.consume(printer, lazyPanelId, widget, widgetType, metaElem);
((LazyCompatibleWidgetConsumer)consumer).handleLazyWholeWidgetCreation(printer, widgetId);
}
else
{
if (dataBindingProcessor == null)
{
dataBindingProcessor = this.dataBindingProcessor;
}
widget = widgetFactory.createWidget(printer, metaElem, widgetId, consumer, dataBindingProcessor);
}
if (widget == null)
{
throw new CruxGeneratorException("Can not create widget ["+widgetId+"]. Verify the widget type.");
}
return widget;
}
/**
* @param context
* @param changed
* @param view
* @param device
*/
protected void prepare(RebindContext context, boolean changed, View view, String device)
{
this.context = context;
this.view = view;
this.lazyPanels.clear();
this.declaredMessages.clear();
this.postProcessingCode.clear();
this.device = device;
this.rootPanelChildren.clear();
this.viewChanged = changed;
if (context != null)
{
this.controllerAccessHandler = new DefaultControllerAccessor(viewVariable, context.getControllers());
this.bindHandler = new ViewBindHandler(context, view, this);
}
else
{
this.controllerAccessHandler = null;
this.bindHandler = null;
}
}
/**
* Print code that will be executed after the viewFactory completes the widgets construction.
* Note that this code will be executed from inside a Command class. Any variable accessed in
* this code and declared outside need to be declared as final.
*
* @param s code string
*/
protected void printlnPostProcessing(String s)
{
this.postProcessingCode.getLast().postProcessingPrinter.println(s);
}
/**
* Generate the code for the View events creation
*
* @param printer
*/
protected void processViewEvents(SourcePrinter printer)
{
processHistoryChangedEvt(printer);
processClosingEvt(printer);
processCloseEvt(printer);
processResizedEvt(printer);
processLoadEvt(printer);
processUnloadEvt(printer);
processActivateEvt(printer);
processDeactivateEvt(printer);
}
/**
* Inform the factory that the given widget needs to be available for postProcessing
* @param widgetId widget identifier
*/
protected void registerWidgetForPostProcessing(String widgetId)
{
this.postProcessingCode.getLast().referencedWidgets.add(widgetId);
}
/**
*
* @param text
* @return
*/
protected String resolveI18NString(String text)
{
if (text == null)
{
return null;
}
Matcher matcher = RegexpPatterns.REGEXP_CRUX_MESSAGE.matcher(text);
int pos = 0;
StringBuilder result = new StringBuilder();
while (matcher.find())
{
if (pos != matcher.start())
{
String literal = text.substring(pos, matcher.start());
if (result.length() > 0)
{
result.append("+");
}
result.append(EscapeUtils.quote(literal));
}
pos = matcher.end();
String group = matcher.group();
if (result.length() > 0)
{
result.append("+");
}
result.append(getDeclaredMessage(group));
}
if (pos != text.length())
{
if (result.length() > 0)
{
result.append("+");
}
result.append(EscapeUtils.quote(text.substring(pos)));
}
return result.toString();
}
protected boolean targetsDevice(JSONObject child)
{
Device device = (getDevice() == null?null:Device.valueOf(getDevice()));
if (device == null)
{
return true;
}
String sizeAttr = child.optString("size");
if (!StringUtils.isEmpty(sizeAttr))
{
Size size = Size.valueOf(sizeAttr);
if (!size.equals(device.getSize()))
{
return false;
}
}
String inputAttr = child.optString("input");
if (!StringUtils.isEmpty(inputAttr))
{
Input input = Input.valueOf(sizeAttr);
if (!input.equals(device.getInput()))
{
return false;
}
}
return true;
}
/**
* Gets the list of classes used by the ViewFactory.
*
* @return
*/
String[] getImports()
{
String[] imports = new String[] {
GWT.class.getCanonicalName(),
org.cruxframework.crux.core.client.screen.Screen.class.getCanonicalName(),
org.cruxframework.crux.core.client.screen.views.View.class.getCanonicalName(),
StringUtils.class.getCanonicalName(),
Window.class.getCanonicalName(),
ViewFactoryUtils.class.getCanonicalName(),
ViewFactory.CreateCallback.class.getCanonicalName(),
RootPanel.class.getCanonicalName(),
RootLayoutPanel.class.getCanonicalName(),
Element.class.getCanonicalName(),
Node.class.getCanonicalName(),
ViewLoadEvent.class.getCanonicalName(),
Panel.class.getCanonicalName(),
InterfaceConfigException.class.getCanonicalName(),
Widget.class.getCanonicalName(),
Crux.class.getCanonicalName()
};
return imports;
}
/**
* @return the widgetConsumer
*/
WidgetConsumer getScreenWidgetConsumer()
{
return widgetConsumer;
}
/**
* Checks if declared message is valid
* @param messageClassName
* @param messageKey
* @param messageMethod
* @throws CruxGeneratorException
*/
private void checkDeclaredMessage(String messageClassName, String messageKey, String messageMethod) throws CruxGeneratorException
{
if (StringUtils.isEmpty(messageClassName))
{
throw new CruxGeneratorException("Message ["+messageKey+"] , declared on view ["+view.getId()+"], not found.");
}
else
{
JClassType messageClass = context.getGeneratorContext().getTypeOracle().findType(messageClassName);
if (messageClass == null)
{
String message = "Message class ["+messageKey+"] , declared on view ["+view.getId()+"], could not be loaded. "
+ "\n Possible causes:"
+ "\n\t 1. Check if any type or subtype used by message refers to another module and if this module is inherited in the .gwt.xml file."
+ "\n\t 2. Check if your message or its members belongs to a client package."
+ "\n\t 3. Check the versions of all your modules."
;
throw new CruxGeneratorException(message);
}
else
{
if (!hasMethod(messageClass, messageMethod, new JType[]{}))
{
throw new CruxGeneratorException("Method ["+messageMethod+"] of message ["+messageKey+"], declared on view ["+view.getId()+"], does not exist in message class ["+messageClassName+"].");
}
}
}
}
/**
* Generate the code for a widget creation, based on its metadata.
*
* @param printer
* @param metaElem
* @param widgetType
* @return
*/
private String createWidget(SourcePrinter printer, JSONObject metaElem, String widgetType)
{
if (!metaElem.has("id"))
{
throw new CruxGeneratorException("The id attribute is required for CRUX Widgets. " +
"On page ["+view.getId()+"], there is an widget of type ["+widgetType+"] without id.");
}
String widget;
String widgetId = metaElem.optString("id");
if (widgetId == null || widgetId.length() == 0)
{
throw new CruxGeneratorException("The id attribute is required for CRUX Widgets. " +
"On page ["+view.getId()+"], there is an widget of type ["+widgetType+"] without id.");
}
widget = newWidget(printer, metaElem, widgetId, widgetType);
if (isAttachToDOM(widgetType))
{
this.rootPanelChildren.add(widgetId);
}
return widget;
}
/**
* @param printer
*/
private void generateCreateDataSourceMethod(SourcePrinter printer)
{
printer.println("public "+DataSource.class.getCanonicalName()+"<?> createDataSource(String dataSource){");
printer.println("return this.registeredDataSources.getDataSource(dataSource);");
printer.println("}");
}
/**
* @param printer
*/
private void generateCreateWidgetsMethod(SourcePrinter printer)
{
createPostProcessingScope();
printer.println("protected void createWidgets(){");
String viewHTML = getViewHTML();
printer.println("this."+viewPanelVariable+" = new " +
ViewPanel.class.getCanonicalName() + "("+viewHTML+");");
if (!StringUtils.isEmpty(view.getStyleName()))
{
printer.println("this."+viewPanelVariable+".setStyleName("+EscapeUtils.quote(view.getStyleName())+");");
}
processViewEvents(printer);
processViewDimensions(printer);
generateDataProvidersCreationBlock(printer);
generateWidgetsCreationBlock(printer);
generateNativeDataBindingsBlock(printer);
printer.println("if ("+LogConfiguration.class.getCanonicalName()+".loggingIsEnabled()){");
printer.println(loggerVariable+".fine(Crux.getMessages().viewContainerViewCreated(getId()));");
printer.println("}");
printer.println("}");
}
private void generateDataProvidersCreationBlock(SourcePrinter printer)
{
Iterator<DataProvider> dataProviders = view.iterateDataProviders();
while (dataProviders.hasNext())
{
DataProvider dataProvider = dataProviders.next();
try
{
String dataProviderVariable = dataProviderHelper.createDataProvider(printer, dataProvider);
printer.println("addDataProvider("+EscapeUtils.quote(dataProvider.getId())+", "+dataProviderVariable+");");
}
catch (Exception e)
{
throw new CruxGeneratorException("Error Creating dataProvider. See Log for more detail.", e);
}
}
}
/**
* @param printer
*/
private void generateGetRegisteredControllersMethod(SourcePrinter printer)
{
printer.println("public "+RegisteredControllers.class.getCanonicalName()+" getRegisteredControllers(){");
printer.println("return this.registeredControllers;");
printer.println("}");
}
/**
* @param printer
*/
@Deprecated
private void generateGetRegisteredFormattersMethod(SourcePrinter printer)
{
printer.println("public "+RegisteredClientFormatters.class.getCanonicalName()+" getRegisteredFormatters(){");
printer.println("return this.registeredFormatters;");
printer.println("}");
}
/**
*
* @param printer
*/
private void generateInitializeLazyDependenciesMethod(SourcePrinter printer)
{
printer.println("protected native "+org.cruxframework.crux.core.client.collection.Map.class.getCanonicalName()+"<String> initializeLazyDependencies()/*-{");
printer.println("return "+view.getLazyDependencies().toString()+";");
printer.println("}-*/;");
}
private void generateNativeDataBindingsBlock(SourcePrinter printer)
{
Iterator<NativeDataBinding> nativeDataBindings = view.iterateNativeDataBindings();
Set<String> nativeWrappers = new HashSet<String>();
while(nativeDataBindings.hasNext())
{
NativeDataBinding nativeDataBinding = nativeDataBindings.next();
String nativeWrapper = createVariableName("nativeWrapper");
String nativeWrapperClassName = NativeWrapper.class.getCanonicalName();
if (!nativeWrappers.contains(nativeDataBinding.getElementId()))
{
printer.println(nativeWrapperClassName + " " + nativeWrapper + "= this."+viewPanelVariable+".wrapNative(" +
EscapeUtils.quote(nativeDataBinding.getElementId()) + ");");
getScreenWidgetConsumer().consume(printer, nativeDataBinding.getElementId(), nativeWrapper, null, null);
nativeWrappers.add(nativeDataBinding.getElementId());
}
PropertyBindInfo binding = getObjectDataBinding(nativeDataBinding.getBinding(), nativeWrapperClassName,
nativeDataBinding.getAttributeName(), !nativeDataBinding.getAttributeName().equals("value"),
null, null, this.dataBindingProcessor);
WidgetCreatorContext ctx = new WidgetCreatorContext();
ctx.setWidgetId(nativeDataBinding.getElementId());
if (binding != null)
{
ctx.registerObjectDataBinding(binding);
}
else
{
ExpressionDataBinding expressionBinding = getExpressionDataBinding(nativeDataBinding.getBinding(), nativeWrapperClassName,
nativeDataBinding.getAttributeName(), null, null,
this.dataBindingProcessor, null,
DataBindingNativeTypeResolver.resolveTypeForProperty(nativeDataBinding.getAttributeName()).getType());
if (expressionBinding != null)
{
ctx.registerExpressionDataBinding(expressionBinding);
}
}
dataBindingProcessor.processBindings(printer, ctx);
}
}
/**
* @param printer
*/
private void generateRenderMethod(SourcePrinter printer)
{
String rootPanelVariable = createVariableName("rootPanel");
printer.println("protected void render("+Panel.class.getCanonicalName()+" "+rootPanelVariable+", final "+RenderCallback.class.getCanonicalName()+" renderCallback) throws InterfaceConfigException{");
printer.println("if (!this."+viewPanelInitializedVariable+"){");
String viewHTML = getViewHTML();
boolean hasScript = viewHTML.indexOf("<script") >= 0;
if (hasScript)
{
printer.println("this."+viewPanelVariable+".addAttachHandler(new "+Handler.class.getCanonicalName()+"(){");
printer.println("private boolean scriptsProcessed = false;");
printer.println("public void onAttachOrDetach("+AttachEvent.class.getCanonicalName()+" event){");
printer.println("if (event.isAttached()){");
printer.println("if (!scriptsProcessed){");
printer.println(ScriptTagHandler.class.getCanonicalName()+".evaluateScripts("+getProxySimpleName()+".this."+viewPanelVariable+".getElement(), " +
"new " + ScriptTagHandler.ScriptLoadCallback.class.getCanonicalName()+"(){");
printer.println("public void onLoaded(){");
printer.println("renderCallback.onRendered();");
printer.println("}");
printer.println("});");
printer.println("scriptsProcessed = true;");
printer.println("} else {");
printer.println("renderCallback.onRendered();");
printer.println("}");
printer.println("}");
printer.println("}");
printer.println("});");
}
printer.println(rootPanelVariable+".add(this."+viewPanelVariable+");");
for (String widgetId : rootPanelChildren)
{
String lazyPanelId = ViewFactoryUtils.getLazyPanelId(widgetId, LazyPanelWrappingType.wrapWholeWidget);
String widgetViewId;
if (lazyPanels.contains(lazyPanelId))
{
widgetViewId = lazyPanelId;
}
else
{
widgetViewId = widgetId;
}
printer.println("this."+viewPanelVariable+".addAndReplaceElement(widgets.get("+EscapeUtils.quote(widgetViewId)+"), " +
"ViewFactoryUtils.getEnclosingPanelId("+EscapeUtils.quote(widgetId)+", "+viewVariable+"));");
}
if (!hasScript)
{
printer.println("renderCallback.onRendered();");
}
commitPostProcessing(printer);
printer.println("this."+viewPanelInitializedVariable+"=true;");
printer.println("}");
printer.println("else {");
printer.println(rootPanelVariable+".add(this."+viewPanelVariable+");");
if (!hasScript)
{
printer.println("renderCallback.onRendered();");
}
printer.println("}");
printer.println("if(!StringUtils.isEmpty(this.width)){");
printer.println("updateViewWidth(this.width);");
printer.println("}");
printer.println("if(!StringUtils.isEmpty(this.height)){");
printer.println("updateViewHeight(this.height);");
printer.println("}");
printer.println("if ("+LogConfiguration.class.getCanonicalName()+".loggingIsEnabled()){");
printer.println(loggerVariable+".fine(Crux.getMessages().viewContainerViewRendered(getId()));");
printer.println("}");
printer.println("}");
}
private void generateUpdateDimensionsMethods(SourcePrinter printer)
{
printer.println("protected void updateViewHeight(String height){");
printer.println("if (this."+viewPanelVariable+" != null){");
printer.println("this."+viewPanelVariable+".setHeight(height);");
printer.println("}");
printer.println("}");
printer.println("protected void updateViewWidth(String width){");
printer.println("if (this."+viewPanelVariable+" != null){");
printer.println("this."+viewPanelVariable+".setWidth(width);");
printer.println("}");
printer.println("}");
}
private void generateWidgetsCreationBlock(SourcePrinter printer)
{
Iterator<org.cruxframework.crux.core.rebind.screen.Widget> widgets = view.iterateWidgets();
while (widgets.hasNext())
{
org.cruxframework.crux.core.rebind.screen.Widget widget = widgets.next();
if (widget.getParent() == null)
{
JSONObject metaElement = widget.getMetadata();
try
{
String type = getMetaElementType(metaElement);
createWidget(printer, metaElement, type);
}
catch (Exception e)
{
throw new CruxGeneratorException("Error Creating widget. See Log for more detail.", e);
}
}
}
}
/**
*
* @return
*/
private String getViewHTML()
{
return getViewHTML(view.getHtml());
}
/**
* Verifies if a method exists into a interface
* @param clazz
* @param methodName
* @param params
* @return
*/
private boolean hasMethod(JClassType clazz, String methodName, JType[] params)
{
if (clazz != null && methodName != null)
{
JMethod method = clazz.findMethod(methodName, params);
if (method != null)
{
return true;
}
JClassType[] interfaces = clazz.getImplementedInterfaces();
if (interfaces != null)
{
for (JClassType intf : interfaces)
{
if (hasMethod(intf, methodName, params))
{
return true;
}
}
}
}
return false;
}
/**
* Returns <code>true</code> if widgets of the given type should be attached to DOM after instantiated.
* @param widgetType
* @return <code>true</code> if widgets of the given type should be attached to DOM after instantiated.
*/
private boolean isAttachToDOM(String widgetType)
{
if (!attachToDOMFactories.containsKey(widgetType))
{
DeclarativeFactory declarativeFactory = getWidgetCreator(widgetType).getClass().getAnnotation(DeclarativeFactory.class);
attachToDOMFactories.put(widgetType, declarativeFactory.attachToDOM());
}
return attachToDOMFactories.get(widgetType);
}
/**
* Returns <code>true</code> if the given widget should be rendered lazily
* @param widgetType
* @param metaElem
* @param widgetId
* @return <code>true</code> if the given widget should be rendered lazily
*/
private boolean mustRenderLazily(String widgetType, JSONObject metaElem, String widgetId)
{
Class<?> widgetClass = getWidgetCreator(widgetType).getWidgetClass();
if (Panel.class.isAssignableFrom(widgetClass))
{
if (!metaElem.optBoolean("visible", true))
{
String lazyPanelId = ViewFactoryUtils.getLazyPanelId(widgetId, LazyPanelWrappingType.wrapWholeWidget);
return !lazyPanels.contains(lazyPanelId);
}
}
return false;
}
/**
* Processes the attach event.
*
* @param printer
*/
private void processActivateEvt(SourcePrinter printer)
{
Event onActivate = view.getEvent("onActivate");
if (onActivate != null)
{
printer.println(viewVariable+".addViewActivateHandler(new "+ViewActivateHandler.class.getCanonicalName()+"(){");
printer.println("public void onActivate("+ViewActivateEvent.class.getCanonicalName()+" event){");
EvtProcessor.printEvtCall(printer, onActivate.getController()+"."+onActivate.getMethod(),
"onActivate", ViewActivateEvent.class, "event", context, view, getControllerAccessHandler(), Device.valueOf(device));
printer.println("}");
printer.println("});");
}
}
/**
* Processes the close event.
*
* @param printer
*/
private void processCloseEvt(SourcePrinter printer)
{
Event onClose = view.getEvent("onClose");
if (onClose != null)
{
printer.println(viewVariable+".addWindowCloseHandler(new "+CloseHandler.class.getCanonicalName()+"<Window>(){");
printer.println("public void onClose("+CloseEvent.class.getCanonicalName()+"<Window> event){");
EvtProcessor.printEvtCall(printer, onClose.getController()+"."+onClose.getMethod(), "onClose",
CloseEvent.class, "event", context, view, getControllerAccessHandler(), Device.valueOf(device));
printer.println("}");
printer.println("});");
}
}
/**
* Processes the closing event.
*
* @param printer
*/
private void processClosingEvt(SourcePrinter printer)
{
Event onClosing = view.getEvent("onClosing");
if (onClosing != null)
{
printer.println(viewVariable+".addWindowClosingHandler(new Window.ClosingHandler(){");
printer.println("public void onWindowClosing("+ClosingEvent.class.getCanonicalName()+" event){");
EvtProcessor.printEvtCall(printer, onClosing.getController()+"."+onClosing.getMethod(), "onClosing",
ClosingEvent.class, "event", context, view, getControllerAccessHandler(), Device.valueOf(device));
printer.println("}");
printer.println("});");
}
}
/**
* Processes the attach event.
*
* @param printer
*/
private void processDeactivateEvt(SourcePrinter printer)
{
Event onDeactivate = view.getEvent("onDeactivate");
if (onDeactivate != null)
{
printer.println(viewVariable+".addViewDeactivateHandler(new "+ViewDeactivateHandler.class.getCanonicalName()+"(){");
printer.println("public void onDeactivate("+ViewDeactivateEvent.class.getCanonicalName()+" event){");
EvtProcessor.printEvtCall(printer, onDeactivate.getController()+"."+onDeactivate.getMethod(),
"onDeactivate", ViewDeactivateEvent.class, "event", context, view, getControllerAccessHandler(), Device.valueOf(device));
printer.println("}");
printer.println("});");
}
}
/**
* Processes the historyChanged event.
*
* @param printer
*/
private void processHistoryChangedEvt(SourcePrinter printer)
{
Event onHistoryChanged = view.getEvent("onHistoryChanged");
if (onHistoryChanged != null)
{
printer.println(viewVariable+".addWindowHistoryChangedHandler(new "+ValueChangeHandler.class.getCanonicalName()+"<String>(){");
printer.println("public void onValueChange("+ValueChangeEvent.class.getCanonicalName()+"<String> event){");
EvtProcessor.printEvtCall(printer, onHistoryChanged.getController()+"."+onHistoryChanged.getMethod(),
"onHistoryChanged", ValueChangeEvent.class, "event", context, view, getControllerAccessHandler(), Device.valueOf(device));
printer.println("}");
printer.println("});");
}
}
/**
* Processes the load event.
*
* @param printer
*/
private void processLoadEvt(SourcePrinter printer)
{
Event onLoad = view.getEvent("onLoad");
if (onLoad != null)
{
printer.println(viewVariable+".addViewLoadHandler(new "+ViewLoadHandler.class.getCanonicalName()+"(){");
printer.println("public void onLoad("+ViewLoadEvent.class.getCanonicalName()+" event){");
EvtProcessor.printEvtCall(printer, onLoad.getController()+"."+onLoad.getMethod(),
"onLoad", ViewLoadEvent.class, "event", context, view, getControllerAccessHandler(), Device.valueOf(device));
printer.println("}");
printer.println("});");
}
}
/**
* Processes the resized event.
*
* @param printer
* @return
*/
private Event processResizedEvt(SourcePrinter printer)
{
Event onResized = view.getEvent("onResized");
if (onResized != null)
{
printer.println("screen.addResizeHandler(new "+ResizeHandler.class.getCanonicalName()+"(){");
printer.println("public void onResize("+ResizeEvent.class.getCanonicalName()+" event){");
EvtProcessor.printEvtCall(printer, onResized.getController()+"."+onResized.getMethod(), "onResized",
ResizeEvent.class, "event", context, view, getControllerAccessHandler(), Device.valueOf(device));
printer.println("}");
printer.println("});");
}
return onResized;
}
/**
* Processes the unload event.
*
* @param printer
*/
private void processUnloadEvt(SourcePrinter printer)
{
Event onUnload = view.getEvent("onUnload");
if (onUnload != null)
{
printer.println(viewVariable+".addViewUnloadHandler(new "+ViewUnloadHandler.class.getCanonicalName()+"(){");
printer.println("public void onUnload("+ViewUnloadEvent.class.getCanonicalName()+" event){");
EvtProcessor.printEvtCall(printer, onUnload.getController()+"."+onUnload.getMethod(),
"onUnload", ViewUnloadEvent.class, "event", context, view, getControllerAccessHandler(), Device.valueOf(device));
printer.println("}");
printer.println("});");
}
}
private void processViewDimensions(SourcePrinter printer)
{
if (!StringUtils.isEmpty(this.view.getWidth()))
{
printer.println("setWidth("+EscapeUtils.quote(this.view.getWidth())+");");
}
if (!StringUtils.isEmpty(this.view.getHeight()))
{
printer.println("setHeight("+EscapeUtils.quote(this.view.getHeight())+");");
}
}
/**
* Creates a new unique name based off of{@code varName} and adds it to
* the list of known names.
*
* @param varName
* @return
*/
public static String createVariableName(String varName)
{
return nameFactory.createName(varName);
}
/**
* Retrieve the name of the class responsible for native calls to controller methods.
* @param viewId
* @return
*/
public static String getViewNativeControllersType(String viewId, String device)
{
return viewId.replaceAll("\\W", "_") + "_NativeControllers_" + device;
}
/**
* Retrieves the view variable name
* @return
*/
public static String getViewVariable()
{
return viewVariable;
}
/**
* Split the i18n message and separate the messageClass alias from the message method
*
* @param text
* @return
*/
protected static String[] getKeyMessageParts(String text)
{
text = text.substring(2, text.length()-1);
return text.split("\\.");
}
/**
* Split the resourceReference and separate the resourceClass alias from the requested property
*
* @param text
* @return
*/
protected static String[] getResourceParts(String text)
{
text = text.substring(2, text.length()-1);
int index = text.indexOf('.');
String[] result = new String[2];
result[0] = text.substring(0, index);
result[1] = text.substring(index+1, text.length());
return result;
}
/**
*
* @author Thiago da Rosa de Bustamante
*
*/
public interface DataBindingProcessor
{
String getDataObjectAlias(String dataObject);
String getNativeUiObjectExpression(String elementId);
void processBindings(SourcePrinter out, WidgetCreatorContext context);
}
/**
*
* @author Thiago da Rosa de Bustamante
*
*/
public static class EmptyWidgetConsumer implements WidgetConsumer
{
public void consume(SourcePrinter out, String widgetId, String widgetVariableName, String widgetType, JSONObject metaElem)
{
}
}
/**
*
* @author Thiago da Rosa de Bustamante
*
*/
public interface LazyCompatibleWidgetConsumer extends WidgetConsumer
{
void handleLazyWholeWidgetCreation(SourcePrinter out, String widgetId);
void handleLazyWrapChildrenCreation(SourcePrinter out, String widgetId);
}
/**
*
* @author Thiago da Rosa de Bustamante
*
*/
public interface WidgetConsumer
{
public static EmptyWidgetConsumer EMPTY_WIDGET_CONSUMER = new EmptyWidgetConsumer();
void consume(SourcePrinter out, String widgetId, String widgetVariableName, String widgetType, JSONObject metaElem);
}
private static class DefaultControllerAccessor implements ControllerAccessHandler
{
private ControllerScanner controllersScanner;
private final String viewVariable;
public DefaultControllerAccessor(String viewVariable, ControllerScanner controllersManager)
{
this.viewVariable = viewVariable;
this.controllersScanner = controllersManager;
}
public String getControllerExpression(String controller, Device device)
{
return "(("+getControllerImplClassName(controller, device)+")"+viewVariable+".getController("
+EscapeUtils.quote(controller)+"))";
}
public String getControllerImplClassName(String controller, Device device)
{
String controllerClass;
try
{
controllerClass = controllersScanner.getController(controller, device);
}
catch (ResourceNotFoundException e)
{
throw new CruxGeneratorException("Can not found the controller ["+controller+"]. Check your classpath and the inherit modules");
}
return controllerClass + ControllerProxyCreator.CONTROLLER_PROXY_SUFFIX;
}
}
private static class PostProcessingData
{
PostProcessingPrinter postProcessingPrinter = new PostProcessingPrinter();
Set<String> referencedWidgets = new HashSet<String>();
@Override
public String toString()
{
return postProcessingPrinter.toString();
}
}
/**
* Printer for code that should be executed after the screen creation.
*
* @author Thiago da Rosa de Bustamante
*/
private static class PostProcessingPrinter implements SourcePrinter
{
private StringBuilder builder = new StringBuilder();
private String indentation = "";
@Override
public void commit()
{
// DO Nothing
}
@Override
public void indent()
{
indentation+="\t";
}
@Override
public void outdent()
{
if (indentation.length() > 0)
{
indentation = indentation.substring(1);
}
}
@Override
public void print(String s)
{
builder.append(s);
if (s.equals("\n"))
{
builder.append(indentation);
}
}
@Override
public void println()
{
print("\n");
}
@Override
public void println(String s)
{
String line = s.trim();
if (line.endsWith("}") || line.endsWith("});") || line.endsWith("};") || line.endsWith("}-*/;"))
{
outdent();
}
builder.append(indentation+s+"\n");
if (line.endsWith("{"))
{
indent();
}
}
@Override
public String toString()
{
return builder.toString();
}
}
}